package org.jhulk.states;

import java.util.ArrayList;
import java.util.Iterator;

import org.jhulk.sprites.Marine;
import org.jhulk.sprites.Squad;
import org.jhulk.utils.GameUtils;
import org.jhulk.utils.TileMapUtils;
import org.newdawn.slick.Color;
import org.newdawn.slick.Font;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.XMLPackedSheet;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.tiled.TiledMap;

public class GamePlayState extends BasicGameState 
{
	/** The ID given to this state */
	public static int ID = 0;
	
	private GameCache cache;
	
	/** The font to write the message with */
	private Font font;
	   
	/** The game holding this state */
	private StateBasedGame game;
	
	private STATE currPlayState = STATE.UNIT_PLACEMENT;
	
	private enum STATE
	{
		UNIT_PLACEMENT, PLAY
	}

	public GamePlayState(int id, GameCache cache)
	{
		this.ID = id;
		this.cache = cache;
	}
	
	@Override
	public int getID() {
		return this.ID;
	}

	public void init(GameContainer arg0, StateBasedGame arg1) throws SlickException {
		
		try {
			initCache();
		} catch (SlickException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void initCache() throws SlickException
	{
		cache.setMap( new TiledMap("data/maps/testTileset.tmx") );
		XMLPackedSheet sheet = new XMLPackedSheet("data/img/packedTest.png", "data/img/packedTest.png.xml");
		
		String squadString;
		cache.setSquads( new ArrayList<Squad>() );
		squadString = cache.getMap().getMapProperty("squad1", "");
		Squad curSquad =GameUtils.parseSquadString(squadString, sheet);
		cache.getSquads().add(curSquad);
		cache.addToPlacementQueue(curSquad);
	}


	public void render(GameContainer c, StateBasedGame sbg, Graphics g) throws SlickException {
		
		cache.getMap().render(0, 0);

		//If the cursor is over a valid tile, highlight the tile
		if(cache.getHovTileId() != 0)
			g.drawRect(
					cache.getMapXForTile().floatValue(), 
					cache.getMapYForTile().floatValue(), 
					cache.getMap().getTileWidth(), 
					cache.getMap().getTileHeight());
		
		//Draw a rectangle around the selected character
		if(cache.getSelectedChar() != null)
		{
			g.setColor(Color.cyan);
			Marine selChar = cache.getSelectedChar();
			g.drawRect(
					selChar.getX(), 
					selChar.getY(), 
					cache.getMap().getTileWidth(), 
					cache.getMap().getTileHeight());
		}
		
		//Loop through all characters
		
		////Loop through all squads
		for(Squad s : cache.getSquads()) 
		{
			s.renderSquad();
		}
	}
	
    public void mouseReleased(int button, int x, int y)
    {
    	cache.setCurrTile( TileMapUtils.getMapTileFromClick(x, y, cache.getMap()) );
    	
    	switch(currPlayState)
    	{
    		case UNIT_PLACEMENT:
    			placeMarine();
    			break;
    			
    		case PLAY:
    			determineCharAtClick();
    			break;
    	}
        
    }

    public void placeMarine()
    {
        if(cache.getCurrTile().getId() != -1)
        {
        	for (Iterator<Marine> it = cache.getPlacementQueue().iterator(); it.hasNext (); )
        	{
        		Marine m = it.next();
        		if(m.isPlaced() == false)
    			{
    				m.placeChar(cache.getCurrTile().getMapX(), cache.getCurrTile().getMapY());
    				System.out.println("Placed : " + m.getName());
    				it.remove();
    				break;
    			}
        	}
        	
        	if(cache.getPlacementQueue().size() == 0)
        	{
        		currPlayState = STATE.PLAY;
        		System.out.println("Unit placement phase over, entering PLAY state");
        	}
        }
    }

    public void determineCharAtClick()
    {
    	//loop through the squads for any character that has those coords
    	//TODO: Need to change this to look in ALL characters, not just squads
    	for(Squad s : cache.getSquads())
    	{
    		for(Marine m : s.getAllUnits())
    		{
    			if(m.getX() == cache.getCurrTile().getMapX() && m.getY() == cache.getCurrTile().getMapY())
    			{
    				cache.setSelectedChar( m );
    				System.out.println("Selected character is: " + m.getName());
    			}
    		}
    	}
    }
    
    public void keyPressed(int key, char c)
    {
		if(cache.getSelectedChar() != null)
		{
			if(key == Input.KEY_LCONTROL || key == Input.KEY_RCONTROL) cache.setCtrlPressed( true );
			
	        if(cache.isCtrlPressed())
	        {
	            if(key == Input.KEY_LEFT) cache.getSelectedChar().turnLeft();
	
	            if(key == Input.KEY_RIGHT) cache.getSelectedChar().turnRight();
	        }
	        else
	        {
	            if(key ==  Input.KEY_LEFT && canMoveX(cache.getSelectedChar().getX(), cache.getSelectedChar().getY(), -1))
	            {
	                if(key == Input.KEY_LEFT) cache.getSelectedChar().setX(cache.getSelectedChar().getX() - cache.getSelectedChar().getMoveX()); 
	            }
	
	            if(key == Input.KEY_RIGHT && canMoveX(cache.getSelectedChar().getX(), cache.getSelectedChar().getY(), 1))
	            {
	                if(key == Input.KEY_RIGHT) cache.getSelectedChar().setX(cache.getSelectedChar().getX() + cache.getSelectedChar().getMoveX()); 
	            }
	        }
	
	        if(key == Input.KEY_UP && canMoveY(cache.getSelectedChar().getX(), cache.getSelectedChar().getY(), -1))
	        {
	            if(key == Input.KEY_UP)cache.getSelectedChar().setY(cache.getSelectedChar().getY() - cache.getSelectedChar().getMoveY()); 
	        }
	
	        if(key == Input.KEY_DOWN && canMoveY(cache.getSelectedChar().getX(), cache.getSelectedChar().getY(), 1))
	        {
	            if(key == Input.KEY_DOWN)cache.getSelectedChar().setY(cache.getSelectedChar().getY() + cache.getSelectedChar().getMoveY()); 
	        }
		}

        //if(key == Input.KEY_SPACE) performCharAction();

        if(key == Input.KEY_ESCAPE) System.exit(0);

    }
    
    public void keyReleased(int key, char c)
    {
        if(key == Input.KEY_LCONTROL || key == Input.KEY_RCONTROL)
            cache.setCtrlPressed( false );
    }
    
    /**
     * Check the horizontal bounds
     * @param x
     * @param y
     * @return
     */
    public boolean canMoveX(int x, int y, int dir)
    {
        boolean canMove = false;

        do
        {
            int futureXPos = (dir > 0) ? 
            		(cache.getSelectedChar().getX() + cache.getSelectedChar().getMoveX()) 
            		: 
            		(cache.getSelectedChar().getX() - cache.getSelectedChar().getMoveX());

            System.out.println("Current X pos: " + cache.getSelectedChar().getX());
            System.out.println("-future X position would be: " + futureXPos);

            //Check if there is a valid tileID
            int futureTileId = TileMapUtils.determineTileIdFromXY(futureXPos, cache.getSelectedChar().getY(), cache.getMap());

            if(futureTileId == 0)
            {
                System.out.println("Can't move there, no tile!");
                break;
            }

            //Check if the player can move to the tile or if something is blocking him
            String impassable = cache.getMap().getTileProperty(futureTileId, "impassable", "");
            if(impassable != "")
            {
                System.out.println("There is an impassable item in the way!!");
                break;
            }
            
            //Check if there is another character or item blocking us
            if(GameUtils.detectCollision(futureXPos, cache.getSelectedChar().getY(), cache))
            {
        		System.out.println("There is another character in the way!");
        		break;
            }
            
            canMove = true;
            break;

        } while(true);

        return canMove;
    }
    
    /**
     * Check the vertical bounds
     * @param x
     * @param y
     * @return
     */
    public boolean canMoveY(int x, int y, int dir)
    {
        boolean canMove = false;
        do
        {
            int futureYPos = (dir > 0) ? 
            		(cache.getSelectedChar().getY() + cache.getSelectedChar().getMoveY()) 
            		: 
            		(cache.getSelectedChar().getY() - cache.getSelectedChar().getMoveY());

            System.out.println("Current Y pos: " + cache.getSelectedChar().getY());
            System.out.println("-future Y position would be: " + futureYPos);

            //Check if there is a valid tileID
            int futureTileId = TileMapUtils.determineTileIdFromXY(
            		cache.getSelectedChar().getX(), 
            		futureYPos, 
            		cache.getMap());

            if(futureTileId == 0)
            {
                System.out.println("Can't move there, no tile!");
                break;
            }

            //Check if the player can move to the tile or if something is blocking him
            String impassable = cache.getMap().getTileProperty(futureTileId, "impassable", "");
            
            if(impassable != "")
            {
                System.out.println("There is an impassable item in the way!!");
                break;
            }
            
            //Check if there is another character or item blocking us
            if(GameUtils.detectCollision(cache.getSelectedChar().getX(), futureYPos, cache))
            {
        		System.out.println("There is another character in the way!");
        		break;
            }
            

            canMove = true;
            break;

        } while(true);

        return canMove;
    }
    
    public void mouseMoved(int oldx, int oldy, int newx, int newy)
    {
    	 cache.setHovTileX( TileMapUtils.getTileXfromMapX(newx, cache.getMap()) );
	     cache.setHovTileY( TileMapUtils.getTileYfromMapY(newy, cache.getMap()) );
	     
	     cache.setHovTileId( cache.getMap().getTileId(cache.getHovTileX(), cache.getHovTileY(), 0) );
	     
	     cache.setMapXForTile( new Double(TileMapUtils.getTileXBorderFromMapX(newx, cache.getMap())) );
	     cache.setMapYForTile( new Double(TileMapUtils.getTileYBorderFromMapY(newy, cache.getMap())) );
    }

	public void update(GameContainer arg0, StateBasedGame arg1, int arg2)
			throws SlickException {
		// TODO Auto-generated method stub

	}
}
